SPI DEV使用参考

Version 1.0


1. 概述

本文主要介绍Linux用户环境下SPI driver的使用。


2. SPI控制

2.1. SPI Pads

SPI pad modes 可设定的mode 和脚位对应如下。

表 2‑1:Pudding平台

Spi Group Mode SPI0_CZ SPI0_CK SPI0_DI(MOSI) SPI0_DO(MISO) DEV
SPI 0 1 PAD_I2S0_BCK PAD_I2S0_WCK PAD_I2S0_DI PAD_I2S0_DO /dev/spidev0.0
2 PAD_FUART_RX PAD_FUART_TX PAD_FUART_CTS PAD_FUART_RTS
SPI 1 1 PAD_FUART_RX PAD_FUART_TX PAD_FUART_CTS PAD_FUART_RTS /dev/spidev1.0
2 PAD_GPIO12 PAD_GPIO12 PAD_GPIO12 PAD_GPIO12
5 PAD_PM_SPI_CZ PAD_PM_SPI_CK PAD_PM_SPI_DI PAD_PM_SPI_DO

表 2‑2:Ispahan平台

Spi Group Mode SPI0_CZ SPI0_CK SPI0_DI(MOSI) SPI0_DO(MISO) DEV
SPI 0 1 PAD_SPI0_CZ PAD_SPI0_CK PAD_SPI0_DI PAD_SPI0_DO /dev/spidev0.0
2 PAD_GPIO4 PAD_GPIO5 PAD_GPIO6 PAD_GPIO7
3 PAD_FUART_RX PAD_FUART_TX PAD_FUART_CTS PAD_FUART_RTS
4 PAD_SD1_IO0 PAD_SD1_IO2 PAD_SD1_IO3 PAD_SD1_IO4
SPI 1 3 PAD_SD_D0 PAD_ SD_D1 PAD_ SD_D2 PAD_ SD_D3 /dev/spidev1.0
4 PAD_GPIO0 PAD_ GPIO2 PAD_ GPIO3 PAD_ GPIO

2.2. SPI0的 dts 配置

以 Pudding mode4为例。

如下use-dma表示是否使用DMA,修改 infinity6e.dtsi:

添加 SPI0 padmux 复用

修改 infinity6e-padmux-qfn.dtsi

SPI0 选择 Mode4(PAD_GPIO0/PAD_GPIO1/PAD_GPIO2/PAD_GPIO3)进行输出,没有在其他组输出的话,需要将其他组注释掉。

2.3. SPI1的 dts 配置

以 Ispphand mode4为例。Ispahan无padmux,只需在对应的节点添加pad-ctrl属性,其值为对应mode的CZ pad。

如下 use-dma表示是否使用DMA,修改 infinity6b0.dtsi:


3. KERNEL配置

3.1. 打开 kernel 对 SPI 的配置

3.2. 打开 SStar SPI 驱动配置


4. 用户DEMO

4.1. SPI device

" /dev/spidev1.0” //根据使用哪一组spi确认节点

4.2. Sample code

static const char *device = "/dev/spidev1.0"; //根据使用哪一组spi确认节点
static uint8_t mode = 0; /* SPI通信使用全双工,设置CPOL=0,CPHA=0。 */
static uint8_t bits = 8; /* 8bits读写,MSB first。*/
static uint32_t speed = 60*1000*1000;/* 设置传输速度 */
static uint16_t delay = 0;
static int g_SPI_Fd = 0;

static void pabort(const char *s)
{
    perror(s);
    abort();
}


/**
* 功 能:同步数据传输
* 入口参数 :
* TxBuf -> 发送数据首地址
* len -> 交换数据的长度
* 出口参数:
* RxBuf -> 接收数据缓冲区
* 返回值:0 成功
* 开发人员:Lzy 2013-5-22
*/
int SPI_Transfer(const uint8_t *TxBuf, uint8_t *RxBuf, int len)
{
    int ret;
    int fd = g_SPI_Fd;


    struct spi_ioc_transfer tr ={
        .tx_buf = (unsigned long) TxBuf,
        .rx_buf = (unsigned long) RxBuf,
        .len =len,
        .delay_usecs = delay,
    };


    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
        perror("can't send spi message\n");
    else
    {
#if SPI_DEBUG
        int i;
        printf("nsend spi message Succeed\n");
        printf("nSPI Send [Len:%d]: \n", len);
        for (i = 0; i < len; i++)
        {
            if (i % 8 == 0)
                printf("nt\n");
            printf("0x%02X \n", TxBuf[i]);
        }
        printf("n");


        printf("SPI Receive [len:%d]:\n", len);
        for (i = 0; i < len; i++)
        {
            if (i % 8 == 0)
                printf("nt\n");
            printf("0x%02X \n", RxBuf[i]);
        }
        printf("\n");
#endif
    }
    return ret;
}


/**
* 功 能:发送数据
* 入口参数 :
* TxBuf -> 发送数据首地址
*len -> 发送与长度
*返回值:0 成功
* 开发人员:Lzy 2013-5-22
*/
int SPI_Write(uint8_t *TxBuf, int len)
{
    int ret;
    int fd = g_SPI_Fd;


    ret = write(fd, TxBuf, len);
    if (ret < 0)
        perror("SPI Write error\n");
    else
    {
#if SPI_DEBUG
        int i;
        printf("SPI Write [Len:%d]: \n", len);
        for (i = 0; i < len; i++)
        {
            if (i % 8 == 0)
                printf("\n\t");
            printf("0x%02X \n", TxBuf[i]);
        }
        printf("\n");
#endif
    }

    return ret;
}


/**
* 功 能:接收数据
* 出口参数:
* RxBuf -> 接收数据缓冲区
* rtn -> 接收到的长度
* 返回值:>=0 成功
* 开发人员:Lzy 2013-5-22
*/
int SPI_Read(uint8_t *RxBuf, int len)
{
    int ret;
    int fd = g_SPI_Fd;
    ret = read(fd, RxBuf, len);
    if (ret < 0)
        printf("SPI Read error\n");
    else
    {
#if SPI_DEBUG
        int i;
        printf("SPI Read [len:%d]:\n", len);
        for (i = 0; i < len; i++)
        {
            if (i % 8 == 0)
                printf("\n\t");
            printf("0x%02X \n", RxBuf[i]);
        }
        printf("\n");
#endif
    }
    return ret;
}


/**
* 功 能:打开设备 并初始化设备
* 入口参数 :
* 出口参数:
* 返回值:0 表示已打开 0XF1 表示SPI已打开 其它出错
* 开发人员:Lzy 2013-5-22
*/
int SPI_Open(void)
{
    int fd;
    int ret = 0;


    if (g_SPI_Fd != 0) /* 设备已打开 */
        return 0xF1;

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device\n");
    else
        printf("SPI - Open Succeed. Start Init SPI...\n");


    g_SPI_Fd = fd;
    /*
    * spi mode
    */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        pabort("can't set spi mode\n");


    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        pabort("can't get spi mode\n");


    /*
    * bits per word
    */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word\n");


    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word\n");


    /*
    * max speed hz
    */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz\n");


    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz\n");


    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d KHz (%d MHz)\n", speed / 1000, speed / 1000 / 1000);


    return ret;
}


/**
* 功 能:关闭SPI模块
*/
int SPI_Close(void)
{
    int fd = g_SPI_Fd;


    if (fd == 0) /* SPI是否已经打开*/
        return 0;
    close(fd);
    g_SPI_Fd = 0;


    return 0;
}

/**
* 功 能:自发自收测试程序
* 接收到的数据与发送的数据如果不一样 ,则失败
* 说明:
* 在硬件上需要把输入与输出引脚短跑
* 开发人员:Lzy 2013-5-22
*/
int SPI_LookBackTest(void)
{
    int ret, i;
    const int BufSize = 16;
    uint8_t tx[BufSize], rx[BufSize];

    bzero(rx, sizeof(rx));
    for (i = 0; i < BufSize; i++)
        tx[i] = i;

    printf("nSPI - LookBack Mode Test...\n");
    ret = SPI_Transfer(tx, rx, BufSize);
    if (ret > 1)
    {
        ret = memcmp(tx, rx, BufSize);
        if (ret != 0)
        {
            printf("tx:\n");
            for (i = 0; i < BufSize; i++)
            {
                printf("%d ", tx[i]);
            }
            printf("\n");
            printf("rx:\n");
            for (i = 0; i < BufSize; i++)
            {
                printf("%d ", rx[i]);
            }
            printf("\n");
            perror("LookBack Mode Test error\n");
        }
        else
            printf("SPI - LookBack Mode OK\n");
    }

    return ret;